/**

 * @author ChenJinZhu

 * @date 2023/4/3 14:02

 * @describe : 绘制管线

 */
let canvas = {}, ctx = {};

const image = new Image()

// 定义管线默认宽度
const PIPELINE_NUMBER = 15

const ICON_SCALE_RATIO = 25

// 定义管线流动
let pipeline_offset = 0

// 当前选中的图标
let icon_select = {}

// 定义当前选择绘制的类型 0为管线 1为设备，2为文字框 默认为管线
let selectDrawType = 0

// 定义绘制管线类型：冷0 热1 水
let drawPipelineType = 0
// 定义是否正在绘制管线
let drawPipelineFlay = false
// 定义管线id
let drawPipelineID = 0
// 定义设备id
let deEquipmentID = 0
// 定义文字id
let deTextID = 0

// 所有绘制元素
let allElementCollection = []

// 定义当前选中的已绘制元素
let current_select_element = {}
//定义状态 true 浏览  false 编辑
let svgStateFlay = false

// 绘制实时管线
const drawRealTimePipeline = (e, clickX, clickY, rect) => {
    if (svgStateFlay) {
        return
    }
    drawPipelineFlay = true
    const shape = new PipelineFactory(clickX, clickY)
    let shapeWidth = 0, shapeHeight = 0

    // todo
    // 判断如果线段绘制过短，则不推入 allElementCollection
    allElementCollection.unshift(shape)
    window.onmousemove = (evt) => {
        ctx.clearRect(0, 0, canvas.width, canvas.height)
        shapeWidth = (evt.clientX - rect.left) - clickX
        shapeHeight = (evt.clientY - rect.top) - clickY
        let shapeDirection = Math.abs(shapeWidth) >= Math.abs(shapeHeight);
        if (shapeDirection) {
            shape.endX = evt.clientX - rect.left
            shape.endY = clickY + PIPELINE_NUMBER
        } else {
            shape.endX = clickX + PIPELINE_NUMBER
            shape.endY = evt.clientY - rect.top
        }
        shape.proportion = shapeDirection
        shape.waterType = drawPipelineType
    }
    window.onmouseup = () => {
        if (drawPipelineFlay && shape.endX) {
            //此方法仅在绘制管线结束时执行
            shape.lineID = drawPipelineID
            drawPipelineID++
            //根据lineID进行删除
            if (Math.abs(shape.startX - shape.endX) < 45 && Math.abs(shape.startY - shape.endY) < 45) {
                const index = allElementCollection.findIndex((lin) => {
                    return lin.lineID === shape.lineID;
                })
                allElementCollection.splice(index, 1)
                ctx.clearRect(0, 0, canvas.width, canvas.height)
                removeLineEdit()
            }
            drawPipelineFlay = false
        }
    }
}

// 绘制实时设备
const drawRealTimeEquipment = (e, clickX, clickY, rect) => {
    const shape = new PipelineFactory(clickX, clickY)
    setEquipment(e)

    allElementCollection.push(shape)
    window.onmousemove = (evt) => setEquipment(evt)
    function setEquipment(evt) {
        ctx.clearRect(0, 0, canvas.width, canvas.height)
        shape.startX = evt.clientX - rect.left
        shape.startY = evt.clientY - rect.top
        image.src = require(`../assets/images/${icon_select.iconPath}`);
        let icon_width = Math.ceil(image.width / ICON_SCALE_RATIO),
            icon_height = Math.ceil(image.height / ICON_SCALE_RATIO)
        shape.endX = evt.clientX - rect.left + icon_width
        shape.endY = evt.clientY - rect.top + icon_height
    }

}

// 绘制文字
const drawRealTimeText = (e, clickX, clickY, rect) => {
    const shape = new PipelineFactory(clickX, clickY)
    // const info = allElementCollection[current_select_element]
    // let contentWidth = info && info.content ? ctx.measureText(info.content).width : ctx.measureText('文字描述').width
    // let contentHeight = info && info.contentSize ? info.contentSize : 16

    let contentWidth = ctx.measureText('文字描述').width
    let contentHeight = 16
    setEquipment(e)
    shape.info = { content: '文字描述', contentSize: '16' }
    allElementCollection.push(shape)

    window.onmousemove = (evt) => setEquipment(evt)

    function setEquipment(evt) {
        // console.log(evt.clientX, '//', evt.clientY);
        shape.startX = evt.clientX - rect.left
        shape.startY = evt.clientY - rect.top
        shape.endX = evt.clientX - rect.left + contentWidth
        shape.endY = evt.clientY - rect.top - contentHeight
        ctx.clearRect(0, 0, canvas.width, canvas.height)
        //减去文字高度
    }
}

const moveAllElement = (e, clickX, clickY, rect, shape) => {
    const { startX, startY, endX, endY } = shape
    let tipX = 0, tipY = 0

    // 鼠标左键：拖动位置
    if (e.buttons === 1) {
        window.onmousemove = (evt) => {
            removeLineEdit()
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            const distanceX = evt.clientX - rect.left - clickX
            const distanceY = evt.clientY - rect.top - clickY
            shape.startX = startX + distanceX
            shape.startY = startY + distanceY
            shape.endX = endX + distanceX
            shape.endY = endY + distanceY
        }
    }
    // console.log(current_select_element);
    // 鼠标右键：执行信息编辑
    if (e.buttons === 2) {
        // console.log('rrrrr');
        if (shape.type === 0) {
            // 管线
            tipX = e.clientX
            tipY = e.clientY + 10
        } else if (shape.type === 1) {
            // 如果点击的是图标，弹出提示出现在图标下方
            tipX = (shape.endX - shape.startX) / 2 + shape.startX + rect.left
            tipY = shape.endY + rect.top
        } else if (shape.type === 2) {
            // 文字
            tipX = shape.startX + rect.left + ctx.measureText(`${shape.info.content}`).width / 2
            tipY = shape.startY + rect.top
        }
        createLineEdit(tipX, tipY, shape)
        return false
    }
}


class PipelineFactory {
    constructor(startX, startY, endX, endY) {
        this.startX = startX
        this.startY = startY
        this.endX = endX
        this.endY = endY

        this.type = selectDrawType

        // 管线绘制宽高比 true为横向管线  false为竖向管线
        this.proportion = false
        // 定义管线为热水还是冷水 0为冷水 1为热水
        this.waterType = drawPipelineType

        this.iconPath = icon_select.iconPath

        this.info = {
            name: icon_select.name,
            unit: '°C',
            id: '',
            scale: ICON_SCALE_RATIO,
            rotate: 0,
            show: true,
            value: '33',
            content: '',
            contentSize: '',
            contentColor: '',
            describeList: ['']
        }
    }

    get minX() {
        return Math.min(this.startX, this.endX);
    }
    get maxX() {
        return Math.max(this.startX, this.endX);
    }
    get minY() {
        return Math.min(this.startY, this.endY);
    }
    get maxY() {
        return Math.max(this.startY, this.endY);
    }
    get middleX() {
        return this.endX - (this.endX - this.startX) / 2
    }
    get middleY() {
        return this.endY - (this.endY - this.startY) / 2
    }

    // 绘制管线
    drawPipeline() {
        ctx.beginPath()
        ctx.moveTo(this.minX * devicePixelRatio, this.minY * devicePixelRatio)
        ctx.lineTo(this.maxX * devicePixelRatio, this.minY * devicePixelRatio)
        ctx.lineTo(this.maxX * devicePixelRatio, this.maxY * devicePixelRatio)
        ctx.lineTo(this.minX * devicePixelRatio, this.maxY * devicePixelRatio)
        ctx.lineTo(this.minX * devicePixelRatio, this.minY * devicePixelRatio)
        ctx.fillStyle = '#fff'
        ctx.fill()
        ctx.strokeStyle = '#fff'
        ctx.lineCap = 'square'
        ctx.lineWidth = 1 * devicePixelRatio
        ctx.stroke()
        ctx.beginPath()
        if (this.proportion) {
            ctx.moveTo(this.minX * devicePixelRatio, this.middleY * devicePixelRatio)
            ctx.lineTo(this.maxX * devicePixelRatio, this.middleY * devicePixelRatio)
            ctx.lineDashOffset = this.startX < this.endX ? -pipeline_offset : pipeline_offset;
        } else {
            ctx.moveTo(this.middleX * devicePixelRatio, this.minY * devicePixelRatio)
            ctx.lineTo(this.middleX * devicePixelRatio, this.maxY * devicePixelRatio)
            ctx.lineDashOffset = this.startY < this.endY ? -pipeline_offset : pipeline_offset;
        }
        ctx.strokeStyle = ['#0f42cc', '#ff4316'][this.waterType];
        ctx.lineWidth = 5;
        ctx.setLineDash([15, 15]);
        ctx.stroke()
    }

    // 绘制设备
    drawEquipment() {
        drawIcon.x = this.startX
        drawIcon.y = this.startY
        drawIcon.src = this.iconPath
        drawIcon.rotate = this.info.rotate
        drawIcon.scale = this.info.scale
        drawIcon.show = this.info.show

        drawIcon.draw()
        // 添加文字描述
        if (drawIcon.show) {
            this.drawEquipmentText()
            //如果有描述版文字  克隆后再反转
            if (this.info.describeList[0] != '') {
                var newDescribeList = [...this.info.describeList].reverse()

                newDescribeList.forEach((el, index) => {
                    this.drawDescribeListText(el, index + 1)
                })
            }
        }

    }

    drawEquipmentText() {
        ctx.beginPath()
        ctx.fillStyle = '#000'
        ctx.font = "normal normal normal 16px Microsoft YaHei"
        let fontWidth = ctx.measureText(`${this.info.name}: ${this.info.value} ${this.info.unit}`).width
        let fontX = this.startX + ((this.endX - this.startX - fontWidth) / 2)
        ctx.fillText(`${this.info.name}: ${this.info.value} ${this.info.unit}`, fontX, this.startY - 10)
        ctx.closePath()
    }
    //绘制描述文字
    drawDescribeListText(el, index) {
        ctx.beginPath()
        ctx.fillStyle = '#000'
        ctx.font = "normal normal normal 16px Microsoft YaHei"
        let fontWidth = ctx.measureText(`${el}`).width
        let fontX = this.startX + ((this.endX - this.startX - fontWidth) / 2)
        ctx.fillText(`${el}`, fontX, this.startY - 10 - (20 * index))
        ctx.closePath()
    }
    // 绘制所有
    drawAllElement() {
        // this.type ? this.drawEquipment() : this.drawPipeline()
        switch (this.type) {
            case 0:
                this.drawPipeline()
                break;
            case 1:
                this.drawEquipment()
                break;
            case 2:
                this.drawTimeText()
                break;
            default:
                break;
        }
    }

    // 判断当前点击位置是否在图形内部
    isInside(x, y) {
        return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY
    }

    // 绘制全部文字
    drawTimeText() {
        ctx.beginPath()
        ctx.fillStyle = this.info.contentColor || '#000'
        ctx.font = `normal normal normal ${this.info.contentSize + 'px' || '16px'} Microsoft YaHei`
        // this.info.content 文本内容
        let content = this.info.content
        // let content = `${this.startX},${this.endX},${this.startY},${this.endY}`
        let fontWidth = ctx.measureText(`${content}`).width
        let fontX = this.startX + ((this.endX - this.startX - fontWidth) / 2) // 定位到文字中心
        ctx.fillText(`${content}`, fontX, this.startY)
        ctx.closePath()
    }
}

const drawIcon = {
    w: 50,
    h: 50,
    x: 0,
    y: 0,
    src: '',
    scale: 0,
    rotate: 0,
    draw: function () {
        let img = new Image();
        img.src = require(`../assets/images/${this.src}`);
        ctx.save();

        // 绘制旋转后的图像
        ctx.rotate(this.rotate * Math.PI / 180);
        if (this.rotate === 180) {
            ctx.drawImage(img, (this.x + (img.width / this.scale)) * -1, (this.y + (img.height / this.scale)) * - 1, img.width / this.scale, img.height / this.scale);
        } else if (this.rotate === 90) {
            ctx.drawImage(img, this.y, -this.x - (img.height / this.scale), img.width / this.scale, img.height / this.scale);
        } else if (this.rotate === -90) {
            ctx.drawImage(img, -this.y - (img.width / this.scale), this.x, img.width / this.scale, img.height / this.scale);
        } else {
            ctx.drawImage(img, this.x, this.y, img.width / this.scale, img.height / this.scale);
        }

        ctx.restore();
    }

};

// 鼠标点击canvas查看是否点击到了已经绘制的路线，若是，则返回相关线的对象，若否，返回null
const getPipeline = (x, y) => {
    if (svgStateFlay) {
        return
    }
    for (let i = allElementCollection.length - 1; i >= 0; i--) {
        const element = allElementCollection[i]
        if (element.isInside(x, y)) {
            current_select_element = i
            return element
        }
    }
    return null
}

const canvasMousedown = (e) => {
    removeLineEdit()
    const rect = canvas.getBoundingClientRect();
    const clickX = e.clientX - rect.left;
    const clickY = e.clientY - rect.top;
    // 查询所点击元素是否存在
    const shape = getPipeline(clickX, clickY)
    // console.log(current_select_element);
    if (shape) {
        moveAllElement(e, clickX, clickY, rect, shape)
    } else {
        if (e.buttons === 1) {
            switch (selectDrawType) {
                case 0:
                    // 绘制管线
                    drawRealTimePipeline(e, clickX, clickY, rect)
                    break;
                case 1:
                    // 绘制设备
                    drawRealTimeEquipment(e, clickX, clickY, rect)
                    break;
                case 2:
                    // 绘制文字
                    drawRealTimeText(e, clickX, clickY, rect)
                    break;
                default:
                    break;
            }
        }
    }

}

// 创建管线点击事件弹窗
const createLineEdit = (x, y, shape) => {
    let width = shape.type ? 180 : 120, marginLeft = shape.type ? 95 : 65, display = shape.type ? 'inline-block' : 'none'
    removeLineEdit()
    let tipText = document.createElement('div')
    tipText.classList.add('tip-text-content')
    tipText.innerHTML = `<div class="tip-text" id="tipText" style="top: ${y + 10}px;left: ${x}px; width: ${width}px; margin-left:-${marginLeft}px; ">
                            <p>
                                <span id="equipmentDelete">删除</span>
                                <span id="${shape.type != 2 ? 'equipmentModify' : 'textModify'}" style="display: ${display}">编辑</span>
                                <span id="buttonCancel">取消</span>
                            </p>
                         </div>`
    document.body.appendChild(tipText)

    document.getElementById('equipmentDelete').onclick = (e) => {
        var index = ''
        if (shape.type === 1 || shape.type === 2) {
            //因设备添加id异常所以才用下标删除
            index = current_select_element
        } else {
            index = allElementCollection.findIndex((lin) => {
                return lin.lineID === shape.lineID;
            })
        }
        allElementCollection.splice(index, 1)
        ctx.clearRect(0, 0, canvas.width, canvas.height)
        removeLineEdit()

    }
    let equipmentModifyDom = document.getElementById('equipmentModify')
    if (equipmentModifyDom) {
        equipmentModifyDom.onclick = (e) => {
            removeLineEdit()
        }
    } else {
        document.getElementById('textModify').onclick = (e) => {
            removeLineEdit()
        }
    }


    document.getElementById('buttonCancel').onclick = (e) => {
        removeLineEdit()
    }
}

// 移除管线事件弹窗
const removeLineEdit = () => {
    const popup = document.querySelector('.tip-text-content')
    if (popup) document.body.removeChild(popup)
}

const draw = () => {
    requestAnimationFrame(draw)
    for (const pp of allElementCollection) {
        pp.drawAllElement()
    }
    pipeline_offset++;
    if (pipeline_offset > 300) pipeline_offset = 0
}

const canvasDraw = {
    init(element) {
        canvas = document.getElementById(element)
        ctx = canvas.getContext('2d')

        const w = 1200, h = 800;
        canvas.width = w * devicePixelRatio;
        canvas.height = h * devicePixelRatio;
        canvas.style.width = w + 'px';
        canvas.style.height = h + 'px';

        draw()

        canvas.onmousedown = (e) => canvasMousedown(e)

        canvas.onmouseup = (e) => {
            canvas.onmousemove = null
            window.onmousemove = null
            // removeLineEdit()
        }

        return canvas
    },

    // 回传鼠标抬起事件
    canvasMouseUp: (e) => {
        return allElementCollection[current_select_element]
    },

    // 绘制类型切换
    drawTypeChange: (ele) => {
        if (ele === 2) {
            icon_select = ''
            selectDrawType = 2
            return
        } else {
            icon_select = ele
            selectDrawType = ele.drawType
        }
    },

    // 修改管线类型（冷热水）
    changePipelineType: (type) => {
        drawPipelineType = type
    },

    // 设备参数修改
    modifyIconInfo: (info) => {
        const shape = allElementCollection[current_select_element]
        shape.info = info
        image.src = require(`../assets/images/${shape.iconPath}`);
        let icon_width = Math.ceil(image.width / info.scale),
            icon_height = Math.ceil(image.height / info.scale)
        shape.endX = shape.startX + icon_width
        shape.endY = shape.startY + icon_height
        ctx.clearRect(0, 0, canvas.width, canvas.height)
    },

    // 文字参数修改
    modifyTextInfo: (info) => {
        let shape = allElementCollection[current_select_element]
        let oldInfo = JSON.parse(JSON.stringify(shape.info))
        shape.info = info
        let contentX = parseInt(ctx.measureText(`${info.content}`).width) - parseInt(ctx.measureText(`${oldInfo.content}`).width) // 文本更新前后宽度变化的差值
        let contentY = info.contentSize - oldInfo.contentSize
        shape.endX = shape.endX + contentX
        shape.endY = shape.endY - contentY
        ctx.clearRect(0, 0, canvas.width, canvas.height)
    },
    //  模式切换
    svgStateFlayChange(flay) {
        svgStateFlay = flay
        removeLineEdit()
    },
    //储存时返回数据
    storeData() {
        return allElementCollection
    },
    //清理现有画布
    delSvgData() {
        allElementCollection = []
        ctx.clearRect(0, 0, canvas.width, canvas.height)

    },
    //回显
    echoData(data) {
        allElementCollection = data
        //下方为前后端正式对接所用数据格式 回显处理
        // let echoData = []
        // data.map(item => {
        //     let echoItem = new PipelineFactory()
        //     for (let i in item) {
        //         echoItem[i] = item[i]
        //     }
        //     echoData.push(echoItem)
        //     // console.log(echoItem);
        // })
        // allElementCollection = echoData
    }
}

export default canvasDraw
